import { TreeView } from './view/treeview.js'
import { FormView } from './view/formview.js'
import { SearchView } from './view/search_view.js'

import { fields_helper } from './node_helper.js'

class ActionBase {
  constructor(config, payload = {}) {
    const { rpc, models = {}, metadata } = payload
    this._models_in_config = models
    this._rpc = rpc
    this._config = config
    if (metadata) {
      this._metadata_ready = true
    } else {
      this._metadata_ready = false
    }
    this._metadata = metadata || {}
  }

  get rpc() {
    return this._rpc
  }

  get env() {
    return this.rpc.env
  }

  get config() {
    return this._config
  }

  get views() {
    return this.config.views || {}
  }

  get module() {
    return this.config.module
  }

  get models_in_config() {
    return this._models_in_config
  }

  get fields_in_config() {
    // 这是 配置文件中 的定义
    const in_config = this.config.fields || {}

    const views = { ...this.views }

    const search_view_id = this.config.search_view_id || {}

    if (search_view_id.arch) {
      views.search = { ...search_view_id }
    }

    const in_sheet = fields_helper.fields_get_in_views(views)

    const fs = fields_helper.merge_fields(in_config, in_sheet)

    return fs
  }

  get fields() {
    // action.fields. 仅仅为获取 metadata 服务, 仅包含 嵌套需要的 fields
    function _clean_fields(fields) {
      return Object.keys(fields).reduce((acc, fld) => {
        const done = {}
        const todo = fields[fld] || {}
        if (todo.fields) {
          done.fields = _clean_fields(todo.fields)
        }

        acc[fld] = done
        return acc
      }, {})
    }

    const fields_in_config = this.fields_in_config

    const fields2 = _clean_fields(fields_in_config)
    return fields2
  }

  get metadata() {
    return this._metadata
  }

  get res_model() {
    // 尊重 官方 odoo 的字段命名. 我们在action 配置中使用了 res_model
    // 而在 odoojs 代码中, 习惯上都是使用下面的 model.
    // 所以理论上应该注释到该方法. 禁止使用 res_model 这个名称
    return this.config.res_model
  }

  get model() {
    return this.config.res_model
  }

  get Model() {
    return this.env.model(this.model, { metadata: this.metadata })
  }

  get title() {
    return this.config.name
  }

  get context() {
    // console.log('context', this.config)
    const lang = this.rpc.lang
    const ctx0 = this.env.context || {}
    const ctx = this.config.context || {}
    if (typeof ctx === 'function') {
      const ctx2 = ctx({ env: this.env })
      return { ...ctx0, ...ctx2, lang }
    } else {
      return { ...ctx0, ...ctx, lang }
    }
  }

  get domain() {
    // todo 需要 补 and
    // 这是 action 的强制 domain
    return this.config.domain || []
  }

  get order() {
    return this.config.order || undefined
  }

  get limit() {
    return this.config.limit || 10
  }

  _get_buttons(info) {
    const { buttons = {} } = info
    const btns = { ...buttons }

    if (!('create' in btns)) btns.create = true
    if (!('edit' in btns)) btns.edit = true
    if (!('delete' in btns)) btns.delete = true

    return btns
  }

  get buttons() {
    return this._get_buttons(this.config)
  }

  async check_metadata() {
    if (!this._metadata_ready) {
      return load_metadata()
    }
  }

  async load_metadata(kws = {}) {
    const merge_metadata = res => {
      // 这里返回的就是 服务端的原始的 metadata
      // 页面需要时, 在 get_sheet 函数中, 再做额外处理
      return res
    }

    const { callback } = kws
    const cb = res => {
      this._metadata = merge_metadata(res)
      if (callback) {
        callback(this._metadata)
      }
    }

    const Model = this.env.model(this.model)
    const fields = this.fields
    const context = this.context
    const metadata = await Model.load_metadata({
      fields,
      context,
      callback: cb
    })

    const metadata2 = merge_metadata(metadata)

    this._metadata = metadata2

    this._metadata_ready = true

    return metadata2
  }

  async load_res_id() {
    const { res_id } = this.config
    if (!res_id) {
      return res_id
    } else if (typeof res_id !== 'object') {
      return res_id
    } else {
      const ref_res = await this.env.ref(res_id.ref)
      return ref_res.id
    }
  }
}

export class Action extends ActionBase {
  constructor(action_id, payload = {}) {
    super(action_id, payload)
  }

  _get_view2(info, BaseViewClass) {
    const { creater, ...config } = info
    if (creater && typeof creater === 'function') {
      const ViewClass = creater(BaseViewClass)
      return new ViewClass({ action: this, config })
    } else {
      return new BaseViewClass({ action: this, config })
    }
  }

  _get_view(view_type, BaseViewClass) {
    const info = this.views[view_type] || {}
    return this._get_view2(info, BaseViewClass)
  }

  get search() {
    const info = this.config.search_view_id || {}
    return this._get_view2(info, SearchView)
  }

  get tree() {
    return this._get_view('tree', TreeView)
  }

  get form() {
    return this._get_view('form', FormView)
  }
}
